#ifndef THINK_THINK_MODEL_RELATION_MORPHTO_H
#define THINK_THINK_MODEL_RELATION_MORPHTO_H

static char* think_model_relation_morphto =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: liu21st <liu21st@gmail.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\model\\relation;\n"
	"\n"
	"use think\\Exception;\n"
	"use think\\Loader;\n"
	"use think\\Model;\n"
	"use think\\model\\Relation;\n"
	"\n"
	"class MorphTo extends Relation\n"
	"{\n"
	"    // 多态字段\n"
	"    protected $morphKey;\n"
	"    protected $morphType;\n"
	"    // 多态别名\n"
	"    protected $alias;\n"
	"    protected $relation;\n"
	"\n"
	"    /**\n"
	"     * 构造函数\n"
	"     * @access public\n"
	"     * @param Model  $parent    上级模型对象\n"
	"     * @param string $morphType 多态字段名\n"
	"     * @param string $morphKey  外键名\n"
	"     * @param array  $alias     多态别名定义\n"
	"     * @param string $relation  关联名\n"
	"     */\n"
	"    public function __construct(Model $parent, $morphType, $morphKey, $alias = [], $relation = null)\n"
	"    {\n"
	"        $this->parent    = $parent;\n"
	"        $this->morphType = $morphType;\n"
	"        $this->morphKey  = $morphKey;\n"
	"        $this->alias     = $alias;\n"
	"        $this->relation  = $relation;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前的关联模型类的实例\n"
	"     * @access public\n"
	"     * @return Model\n"
	"     */\n"
	"    public function getModel()\n"
	"    {\n"
	"        $morphType = $this->morphType;\n"
	"        $model     = $this->parseModel($this->parent->$morphType);\n"
	"        return (new $model);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 延迟获取关联数据\n"
	"     * @param string   $subRelation 子关联名\n"
	"     * @param \\Closure $closure     闭包查询条件\n"
	"     * @return mixed\n"
	"     */\n"
	"    public function getRelation($subRelation = \'\', $closure = null)\n"
	"    {\n"
	"        $morphKey  = $this->morphKey;\n"
	"        $morphType = $this->morphType;\n"
	"        // 多态模型\n"
	"        $model = $this->parseModel($this->parent->$morphType);\n"
	"        // 主键数据\n"
	"        $pk            = $this->parent->$morphKey;\n"
	"        $relationModel = (new $model)->relation($subRelation)->find($pk);\n"
	"\n"
	"        if ($relationModel) {\n"
	"            $relationModel->setParent(clone $this->parent);\n"
	"        }\n"
	"        return $relationModel;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 根据关联条件查询当前模型\n"
	"     * @access public\n"
	"     * @param string  $operator 比较操作符\n"
	"     * @param integer $count    个数\n"
	"     * @param string  $id       关联表的统计字段\n"
	"     * @param string  $joinType JOIN类型\n"
	"     * @return Query\n"
	"     */\n"
	"    public function has($operator = \'>=\', $count = 1, $id = \'*\', $joinType = \'INNER\')\n"
	"    {\n"
	"        return $this->parent;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 根据关联条件查询当前模型\n"
	"     * @access public\n"
	"     * @param  mixed  $where 查询条件（数组或者闭包）\n"
	"     * @param  mixed  $fields   字段\n"
	"     * @return Query\n"
	"     */\n"
	"    public function hasWhere($where = [], $fields = null)\n"
	"    {\n"
	"        throw new Exception(\'relation not support: hasWhere\');\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 解析模型的完整命名空间\n"
	"     * @access protected\n"
	"     * @param string $model 模型名（或者完整类名）\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseModel($model)\n"
	"    {\n"
	"        if (isset($this->alias[$model])) {\n"
	"            $model = $this->alias[$model];\n"
	"        }\n"
	"        if (false === strpos($model, \'\\\\\')) {\n"
	"            $path = explode(\'\\\\\', get_class($this->parent));\n"
	"            array_pop($path);\n"
	"            array_push($path, Loader::parseName($model, 1));\n"
	"            $model = implode(\'\\\\\', $path);\n"
	"        }\n"
	"        return $model;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置多态别名\n"
	"     * @access public\n"
	"     * @param array $alias 别名定义\n"
	"     * @return $this\n"
	"     */\n"
	"    public function setAlias($alias)\n"
	"    {\n"
	"        $this->alias = $alias;\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 移除关联查询参数\n"
	"     * @access public\n"
	"     * @return $this\n"
	"     */\n"
	"    public function removeOption()\n"
	"    {\n"
	"        return $this;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 预载入关联查询\n"
	"     * @access public\n"
	"     * @param array    $resultSet   数据集\n"
	"     * @param string   $relation    当前关联名\n"
	"     * @param string   $subRelation 子关联名\n"
	"     * @param \\Closure $closure     闭包\n"
	"     * @return void\n"
	"     * @throws Exception\n"
	"     */\n"
	"    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n"
	"    {\n"
	"        $morphKey  = $this->morphKey;\n"
	"        $morphType = $this->morphType;\n"
	"        $range     = [];\n"
	"        foreach ($resultSet as $result) {\n"
	"            // 获取关联外键列表\n"
	"            if (!empty($result->$morphKey)) {\n"
	"                $range[$result->$morphType][] = $result->$morphKey;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        if (!empty($range)) {\n"
	"            // 关联属性名\n"
	"            $attr = Loader::parseName($relation);\n"
	"            foreach ($range as $key => $val) {\n"
	"                // 多态类型映射\n"
	"                $model = $this->parseModel($key);\n"
	"                $obj   = new $model;\n"
	"                $pk    = $obj->getPk();\n"
	"                $list  = $obj->all($val, $subRelation);\n"
	"                $data  = [];\n"
	"                foreach ($list as $k => $vo) {\n"
	"                    $data[$vo->$pk] = $vo;\n"
	"                }\n"
	"                foreach ($resultSet as $result) {\n"
	"                    if ($key == $result->$morphType) {\n"
	"                        // 关联模型\n"
	"                        if (!isset($data[$result->$morphKey])) {\n"
	"                            throw new Exception(\'relation data not exists :\' . $this->model);\n"
	"                        } else {\n"
	"                            $relationModel = $data[$result->$morphKey];\n"
	"                            $relationModel->setParent(clone $result);\n"
	"                            $relationModel->isUpdate(true);\n"
	"\n"
	"                            $result->setRelation($attr, $relationModel);\n"
	"                        }\n"
	"                    }\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 预载入关联查询\n"
	"     * @access public\n"
	"     * @param Model    $result      数据对象\n"
	"     * @param string   $relation    当前关联名\n"
	"     * @param string   $subRelation 子关联名\n"
	"     * @param \\Closure $closure     闭包\n"
	"     * @return void\n"
	"     */\n"
	"    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n"
	"    {\n"
	"        $morphKey  = $this->morphKey;\n"
	"        $morphType = $this->morphType;\n"
	"        // 多态类型映射\n"
	"        $model = $this->parseModel($result->{$this->morphType});\n"
	"        $this->eagerlyMorphToOne($model, $relation, $result, $subRelation);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 关联统计\n"
	"     * @access public\n"
	"     * @param Model    $result  数据对象\n"
	"     * @param \\Closure $closure 闭包\n"
	"     * @return integer\n"
	"     */\n"
	"    public function relationCount($result, $closure)\n"
	"    {\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 多态MorphTo 关联模型预查询\n"
	"     * @access   public\n"
	"     * @param object $model       关联模型对象\n"
	"     * @param string $relation    关联名\n"
	"     * @param        $result\n"
	"     * @param string $subRelation 子关联\n"
	"     * @return void\n"
	"     */\n"
	"    protected function eagerlyMorphToOne($model, $relation, &$result, $subRelation = \'\')\n"
	"    {\n"
	"        // 预载入关联查询 支持嵌套预载入\n"
	"        $pk   = $this->parent->{$this->morphKey};\n"
	"        $data = (new $model)->with($subRelation)->find($pk);\n"
	"        if ($data) {\n"
	"            $data->setParent(clone $result);\n"
	"            $data->isUpdate(true);\n"
	"        }\n"
	"        $result->setRelation(Loader::parseName($relation), $data ?: null);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 添加关联数据\n"
	"     * @access public\n"
	"     * @param Model     $model  关联模型对象\n"
	"     * @param string    $type   多态类型\n"
	"     * @return Model\n"
	"     */\n"
	"    public function associate($model, $type = \'\')\n"
	"    {\n"
	"        $morphKey  = $this->morphKey;\n"
	"        $morphType = $this->morphType;\n"
	"        $pk        = $model->getPk();\n"
	"\n"
	"        $this->parent->setAttr($morphKey, $model->$pk);\n"
	"        $this->parent->setAttr($morphType, $type ?: get_class($model));\n"
	"        $this->parent->save();\n"
	"\n"
	"        return $this->parent->setRelation($this->relation, $model);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 注销关联数据\n"
	"     * @access public\n"
	"     * @return Model\n"
	"     */\n"
	"    public function dissociate()\n"
	"    {\n"
	"        $morphKey  = $this->morphKey;\n"
	"        $morphType = $this->morphType;\n"
	"\n"
	"        $this->parent->setAttr($morphKey, null);\n"
	"        $this->parent->setAttr($morphType, null);\n"
	"        $this->parent->save();\n"
	"\n"
	"        return $this->parent->setRelation($this->relation, null);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 创建关联统计子查询\n"
	"     * @access public\n"
	"     * @param \\Closure $closure 闭包\n"
	"     * @param string   $name    统计数据别名\n"
	"     * @return string\n"
	"     */\n"
	"    public function getRelationCountQuery($closure, &$name = null)\n"
	"    {\n"
	"        throw new Exception(\'relation not support: withCount\');\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif